package com.foocus.foocuscloud.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPoolUtil {
    public static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtil.class);

    private static ThreadPoolExecutor threadPoolExecutor;

    @PostConstruct
    public static ThreadPoolExecutor initThreadPoolUtil(int core, int maxCore, int maxQueueSize, String poolName) {

        threadPoolExecutor = new ThreadPoolExecutor(core,
                                    maxCore,
                                    60*5,
                                    TimeUnit.SECONDS,
                                    new LinkedBlockingQueue<>(maxQueueSize),
                                    ThreadPoolUtil.defaultFactory(poolName),
                                    new ThreadPoolExecutor.AbortPolicy());
        return threadPoolExecutor;
    }

    @PreDestroy
    public void destroy() {

        threadPoolExecutor.shutdown();
    }

    private static ThreadFactory defaultFactory(String name) {

        return new DefaultThreadPoolFactory(name);
    }

    static class DefaultThreadPoolFactory implements ThreadFactory {

        private final ThreadGroup threadGroup;
        private static String prefixName;
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private static final AtomicInteger threadNumber = new AtomicInteger(1);

        DefaultThreadPoolFactory(String customName) {

            SecurityManager sm = System.getSecurityManager();
            threadGroup = (sm != null) ? sm.getThreadGroup() : Thread.currentThread().getThreadGroup();

            if (customName == null) {
                prefixName = "pool" + poolNumber.getAndIncrement() + "-thread-";
            } else {
                prefixName = customName + "-customThread-";
            }
        }

        @Override
        public Thread newThread(Runnable runnable) {

            Thread thread = new Thread(threadGroup, runnable, prefixName + threadNumber.getAndIncrement());
            if (thread.isDaemon()) {
                thread.setDaemon(false);
            }
            if (thread.getPriority() != Thread.NORM_PRIORITY) {
                thread.setPriority(Thread.NORM_PRIORITY);
            }
            return thread;
        }
    }
}
